package com.bestcem.xm.qdes;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.symmetric.AES;
import lombok.experimental.UtilityClass;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@UtilityClass
public class SignUtil {

    private static final String AES_KEY = ",Qn}V=b?K$8jzKW~";
    //private static final String SURVEY_KEY = "4nbQFHBvRhNCpsq06hToS2diL3mEexhbEbhzYhadlebHzaIY";

    // ECB模式和CBC 模式俩者区别就是 ECB 不需要 iv偏移量，而CBC需要。
    private static final String IV_KEY = "0000000000000000";

    public String genSign(Map<String, Object> map, String signKey) {

        List<String> list = new ArrayList<>();
        List<String> keyList = new ArrayList<>(map.keySet());
        Collections.sort(keyList);
        keyList.forEach(key -> {
            list.add(key);
            Object value = map.get(key);
            if (value instanceof Map) {
                list.add(genSign(BeanUtil.beanToMap(value), signKey));
            } else if (value instanceof List<?>) {
                List<String> strList = new ArrayList<>();
                for (Object v : (List<?>) value) {
                    strList.add(genSignStr(v, signKey));
                }
                list.add(String.join(StrUtil.EMPTY, strList));
            } else if (value instanceof Boolean && !(Boolean) value) {
                list.add(StrUtil.EMPTY);
            } else {
                list.add(String.valueOf(value));
            }
        });
        list.add(signKey);
        return DigestUtil.md5Hex(String.join("|", list));
    }


    public String genSignStr(Object data, String signKey) {
        if (data instanceof Map) {
            return genSign(BeanUtil.beanToMap(data), signKey);
        } else if (data instanceof List<?>) {
            List<String> strList = new ArrayList<>();
            for (Object value : (List<?>) data) {
                strList.add(genSignStr(value, signKey));
            }
            return String.join(StrUtil.EMPTY, strList);
        } else if (data instanceof Boolean && !(Boolean) data) {
            return StrUtil.EMPTY;
        } else {
            return String.valueOf(data);
        }
    }


    public boolean checkSign(Map<String, Object> map, String signKey, String signField) {
        if (Validator.isNull(map)) {
            return false;
        }
        Map<String, Object> copyMap = new HashMap<>(map);
        if (StringUtils.isBlank(signField)) {
            signField = "sig";
        }
        String sign = Convert.toStr(copyMap.get(signField));
        if (StringUtils.isBlank(sign)) {
            return false;
        }
        copyMap.remove(signField);
        // 样本投放的idy_sid由su拼接,不参与验签
        copyMap.remove("idy_sid");
        return sign.equals(genSign(copyMap, signKey));
    }


    public boolean checkSign(Map<String, Object> map, String signKey) {
        return checkSign(map, signKey, "sig");
    }


    public String encryptFromString(String data, Mode mode, Padding padding) {
        AES aes = new AES(mode, padding,new SecretKeySpec(AES_KEY.getBytes(), "AES"));
        return aes.encryptBase64(data, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        String base_link = "http://cloud-dev.bestcem.cn/api/deliver/c_l_deliver/?condition_no=zhuce&system_no=guoshou";
        //http://app.wjdy.sit/api/deliver/c_l_deliver?age=v%2FSptjXg%2BTU8klvpuzGDTA%3D%3D&system_no=lalala&condition_no=wzd&sig=51759de660fd9474fee95042852ced04
        //自定义的外部参数
        Map<String, Object> allmap = new HashMap<>();
        allmap.put("userid", "1378876c84f36af8bd9a33f876c04c31");
        // age这个外部参数要加密
        List<String> needaes = ListUtil.of("userid");
        //List<String> needaes = new ArrayList<>();

        String[] split = base_link.split("\\?");
        String s1 = split[0];//http://app.wjdy.sit/api/deliver/c_l_deliver
        String guding = split[1];//system_no=lalala&condition_no=wzd

        StringBuilder wbcsjm = new StringBuilder();
        needaes.forEach(s -> {
            Object before = allmap.get(s);
            String afteraes = encryptFromString(before.toString(), Mode.ECB, Padding.ZeroPadding);
            try {
                String urlen = URLEncoder.encode(afteraes, "UTF-8");
                //System.out.println(before+"=>>"+urlen);
                wbcsjm.append(s).append("=").append(urlen);
                allmap.put(s, afteraes);
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        });
        //所有外部参数key
        List<String> allkeys = new ArrayList<>(allmap.keySet());
        //Collection<String> disjunction = CollectionUtils.disjunction(Arrays.asList("age","sex"),Arrays.asList("age"));
        //System.out.println(disjunction);
        // 不需要加密的字段
        Collection<String> disjunction = CollectionUtils.disjunction(allkeys, needaes);
        Arrays.stream(guding.split("&")).forEach(s -> {
            String[] ss = s.split("=");
            allmap.put(ss[0], ss[1]);
        });
        String sign = genSign(allmap, AES_KEY);
        //System.out.println(sign);
        String returl;
        //都加密
        if (CollectionUtils.isEmpty(disjunction)) {
            returl = s1 + "?" + wbcsjm + "&" + guding + "&sig=" + sign;
        } else {
            StringBuilder nojm = new StringBuilder();
            disjunction.forEach(s -> nojm.append(s).append("=").append(allmap.get(s).toString()));
            if (StrUtil.isEmptyIfStr(wbcsjm)) {
                //全部参数都没加密
                returl = s1 + "?" + nojm + "&" + guding + "&sig=" + sign;
            } else {
                //部分加密的
                returl = s1 + "?" + nojm + "&" + wbcsjm + "&" + guding + "&sig=" + sign;
            }

        }

        System.out.println(returl);
    }
}
